﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Simulation
{
	class C_EVNT
	{
		F_SETT	ST = new F_SETT();

		C_NODE	ND = new C_NODE();
		C_RPBS	RP = new C_RPBS();
		C_MSSG	MG = new C_MSSG();

		int		RNID;	
		int		EVTY;	/* Event Type */
		int		AQOE;
		int		FRLP;	/* False Injection Report Attack when LEAP */
		
		bool[]	CMND;	/* Compromised Node */
		int[]	PIDS;	/* Partition ID */
		int[]	KEYS;	/* Keys of SEF */

		Random	R = new Random( unchecked( ( int )DateTime.Now.Ticks ) );

		public C_EVNT()
		{
			AQOE = 0;
			EVTY = -1;

			CMND = new bool[ST.OMACS];
			PIDS = new int[ST.OMACS];
			KEYS = new int[ST.OMACS];
		}

		public void SetValues( int T )
		{
			AQOE = T;
		}

		public void SetMAC( int i, bool cmnd, int pids, int keys )
		{
			this.CMND[i] = cmnd;
			this.PIDS[i] = pids;
			this.KEYS[i] = keys;
		}

		public int RandEvent( C_NODE[] SN )
		{
			int evnt = -1;
			
			if ( ( ST.OFRIA == C_COMM.TRUE ) || ( ST.OSINK == C_COMM.TRUE ) )
				evnt = ChooseEvent( R.Next( 0, 99 ) );
			else
				evnt = C_COMM.SCND;				

			switch ( evnt )
			{
				case C_COMM.CNMD:
					if ( ST.OFRIA == C_COMM.TRUE )
					{
						RNID = ChooseCompromisedNode( SN );
						EVTY = C_COMM.CNMD;
					}
					break;
				case C_COMM.SKND:
					if ( ST.OSINK == C_COMM.TRUE )
					{
						RNID = ChooseSinkNode( SN );
						EVTY = C_COMM.SKND;
					}
					break;
				case C_COMM.SCND:
					RNID = R.Next( 0, ST.OTTND );
					EVTY = C_COMM.SCND;
					break;
			}

			return RNID;
		}

		public int ChooseCompromisedNode( C_NODE[] SN )
		{
			int cmnd = -1;

			while( true )
			{
				cmnd = R.Next( 1, ST.OTTND );

				if ( SN[cmnd].CMND == true )
					return cmnd;
			}
		}

		public int ChooseSinkNode( C_NODE[] SN )
		{
			
			for ( int i = 1; i < ST.OTTND; i++ )
			{
				if ( SN[i].SKND == true )
					return i;
			}

			return -1;
		}

		public int ChooseEvent( int R )
		{
			if ( ( 0 >= R ) && ( R <= ST.OFRAR ) )
				return C_COMM.CNMD;
			else if ( ( ST.OFRAR + 1 >= R ) && ( R <= ST.OFRAR + ST.OFRIR ) )
				return C_COMM.SKND;
			else
				return C_COMM.SCND;
		}

		public int RandKey()
		{
			RNID = R.Next( 1, ST.OSKEY );
			return RNID;
		}

		public void TransmitReport( C_NODE[] SN )
		{
			int		ndid = -1;
			int		mvid = -1;			

			for ( int i = 0; i < AQOE; i++ )
			{
				ndid = RandEvent( SN );

				if ( EVTY == C_COMM.SKND )
				{
					MakeFalseRoutingMessage( SN );
					continue;
				}

				SN[ndid].ENGY = ND.ConsumeEnergyForGeneratingMAC( SN[ndid].ENGY );
				GenerateMACs( ndid, SN );
				
				if ( CheckFalseReport( ndid ) )
					SN[ndid].CTFR++;

				if ( ST.OPPMT == C_COMM.TRUE )
				{
					if ( DropFalseReport( SN[ndid].SPID, 1 ) )
					{
						SN[ndid].DFRC++;
						continue;
					}
				}

				while( true )
				{
					SN[ndid].MGCT++;
					SN[ndid].ENGY = ND.ConsumeTransmitting( SN[ndid].ENGY );
					mvid = SN[ndid].PRID;
					
					if ( mvid == -1 )
					{
						SN[ndid].RPER++;
						break;
					}

					//Detect False MACs 
					if ( ST.OSEFF == C_COMM.TRUE )
					{
						if ( DropFalseReport( SN[ndid].SPID, 0 ) )
						{
							SN[ndid].DFRC++;
							break;
						}
					}

					if ( SN[mvid].NDID == 0 )
						break;

					SN[mvid].ENGY = ND.CunsumeReceiving( SN[mvid].ENGY );
					ndid = mvid;
				}
			}
		}

		public bool CheckFalseReport( int ndid )
		{
			for ( int i = 0; i < ST.MACS; i++ )
			{
				if ( CMND[i] == true )
					return true;
			}

			return false;
		}

		// ************** [ Parameters Explaination ] ***************//
		// ndpd:	PID of Intermediate Node 
		// type:	0: SEF	/ 1: Proposed Method
		//***********************************************************//
		public bool DropFalseReport( int ndpd, int type )
		{
			for ( int i = 0; i < ST.MACS; i++ )
			{
				switch ( type )
				{
					case 0:
						if ( ( ndpd == PIDS[i] ) && ( CMND[i] == true ) )
							return true;
						break;
					case 1:
						if ( CMND[i] == true )
							return true;
						break;
				}				
			}

			return false;
		}

		public void GenerateMACs( int id, C_NODE[] SN )
		{
			float	cost = -1.0f;
			int		cntt = 0;
			
			for ( int i = 1; i < ST.OTTND; i++ )
			{
				RP.SetLocation( SN[id].POSX, SN[i].POSX, SN[id].POSY, SN[i].POSY );
				cost = RP.MeasureDistance();

				if ( cntt >= ST.OMACS )
					break;
				
				if ( cost <= ST.ORANG )
				{				
					SN[i].ENGY = ND.ConsumeEnergyForGeneratingMAC( SN[i].ENGY );

					// LEAP만 사용하여 실험할 때 사용
					if ( ( ST.OSEFF == 0 ) && ( ST.OLEAP == 1 ) )
					{
						if ( ( SN[i].CMND == true ) || ( EVTY == C_COMM.CNMD ) )
							SetMAC( cntt, true, 0, 0 );
						else
							SetMAC( cntt, false, 0, 0 );

						cntt++;
						
						continue;
					}

					//Make MACs
					if ( ( SN[i].CMND == true ) || ( EVTY == C_COMM.CNMD ) )
						SetMAC( cntt, true, SN[i].SPID, SN[i].SKEY[RandKey()] );
					else
						SetMAC( cntt, false, SN[i].SPID, SN[i].SKEY[RandKey()] );

					cntt++;
				}
			}
		}

		public void MakeFalseRoutingMessage( C_NODE[] SN )
		{
			int		id		= -1;
			float	cost	= -1.0f;

			for ( int i = 1; i < ST.OTTND; i++ )
			{
				if ( SN[i].SKND == true )
				{
					id = i;
					break;
				}
			}


			for ( int i = 0; i < ST.OTTND; i++ )
			{
				RP.SetLocation( SN[id].POSX, SN[i].POSX, SN[id].POSY, SN[i].POSY );
				cost = RP.MeasureDistance();

				if ( cost <= ST.ORANG )
				{
					SN[id].ENGY = ND.ConsumeTransmitting( SN[id].ENGY );
					SN[id].CTFM++;
					
					SN[i].ENGY = ND.CunsumeReceiving( SN[i].ENGY );
					SN[i].MGCT++;
					SN[i].DFMC++;
				}
			}
		}
	}
}
